package jmine.tec.script.persistent.processor;

import static jmine.tec.script.persistent.domain.enumx.BaseScriptPurposeIdentifier.API;
import static jmine.tec.script.persistent.domain.enumx.BaseScriptPurposeIdentifier.INIT;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.API_PREFIX;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.DATABASE_ID;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.DESCRICAO;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.FINALIDADE;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.INJECT_TEMPLATE;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.LINGUAGEM;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.MNEMONICO;
import static jmine.tec.script.persistent.services.incluir.AbstractScriptService.TEXTO;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import jmine.tec.script.persistent.ScriptPersistenceMessages;
import jmine.tec.script.persistent.dao.ScriptLanguageDAO;
import jmine.tec.script.persistent.domain.ScriptLanguage;
import jmine.tec.script.persistent.domain.ScriptPurpose;
import jmine.tec.script.persistent.driver.ScriptBean;
import jmine.tec.script.persistent.services.incluir.InitScriptService;
import jmine.tec.script.persistent.services.incluir.ScriptService;
import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.export.impl.ExportUtils;
import jmine.tec.services.io.ServiceBean;
import jmine.tec.services.io.ServicesPageBean;
import bancosys.tec.datadigester.DataDigesterException;
import bancosys.tec.persist.controller.PersistenceEnabledController;
import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.services.input.driver.processor.AbstractServiceProcessor;

/**
 * Processor de criação de script
 * 
 * @author lundberg
 * @param <S> tipo de scriptbean
 */
public class ScriptProcessor<S extends ScriptBean> extends AbstractServiceProcessor<S> {

    private PersistenceEnabledController controller;

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<ServicesPageBean> createServicePages(S bean) {
        ScriptLanguage language = this.findLanguage(bean);
        ScriptPurpose purpose = this.findPurpose(bean);

        String mnemonico;
        if (purpose.isIdentifiedBy(API) || purpose.isIdentifiedBy(INIT)) {
            mnemonico = String.format("%s_%s", bean.getMnemonico(), language.getAbreviacao());
        } else {
            mnemonico = bean.getMnemonico();
        }

        ServicesPageBean page = new ServicesPageBean();
        ServiceBean service = new ServiceBean();
        service.setAction(ActionsEnum.INCLUIR);
        service.setName(this.getServiceName());
        service.putParameter(DATABASE_ID, bean.getDatabaseId());
        service.putParameter(FINALIDADE, bean.getFinalidade());
        for (Map.Entry<String, String> dependency : bean.getDependencies().entrySet()) {
            service.putParameter(String.format(INJECT_TEMPLATE, dependency.getKey()), dependency.getValue());
        }
        int apiCount = 0;
        for (String api : bean.getApis()) {
            service.putParameter(String.format("%s %s", API_PREFIX, apiCount++), String.format("%s_%s", api, language.getAbreviacao()));
        }
        service.putParameter(TEXTO, bean.getBody());
        service.putParameter(DESCRICAO, bean.getDescricao());
        service.putParameter(LINGUAGEM, language.getMnemonico());
        service.putParameter(MNEMONICO, mnemonico);

        page.addService(service);
        this.fillSpecific(bean, service);

        if (purpose.isIdentifiedBy(INIT) && service.getAction().incluir()) {
            ServiceBean initScriptService = new ServiceBean();
            initScriptService.setAction(ExportUtils.getServiceAction(InitScriptService.class));
            initScriptService.setName(ExportUtils.getServiceName(InitScriptService.class));
            initScriptService.putParameter(InitScriptService.SCRIPT, mnemonico);
            initScriptService.putParameter(InitScriptService.FINALIDADE, bean.getMnemonico());
            page.addService(initScriptService);
        }
        return Collections.singletonList(page);
    }

    /**
     * Retorna o nome dos serviços utilizados para inclusão de alteração.
     * 
     * @return string
     */
    protected String getServiceName() {
        return ExportUtils.getServiceName(ScriptService.class);
    }

    /**
     * Preenche o ServiceBean com parâmetros específicos do serviço de inclusão ou alteração de script.
     * 
     * @param bean bean
     * @param service service
     */
    protected void fillSpecific(S bean, ServiceBean service) {
        // OK
    }

    /**
     * Encontra o propósito do script
     * 
     * @param bean bean
     * @return script purpose
     */
    private ScriptPurpose findPurpose(ScriptBean bean) {
        BaseDAO<ScriptPurpose> dao = this.controller.getDAOFactory().getGenericDAO(ScriptPurpose.class);
        try {
            return dao.findByNaturalKey(bean.getFinalidade());
        } catch (BeanNotFoundException e) {
            throw new DataDigesterException(ScriptPersistenceMessages.PROCESSOR_PURPOSE_NOT_FOUND.create(bean.getFinalidade()), e);
        }
    }

    /**
     * Encontra a linguagem do script
     * 
     * @param bean bean
     * @return script language
     */
    private ScriptLanguage findLanguage(ScriptBean bean) {
        ScriptLanguageDAO dao = this.controller.getDAOFactory().getDAOByClass(ScriptLanguageDAO.class);
        return dao.findBySystemIdentifier(bean.getLanguageIdentifier());
    }

    /**
     * @param controller the controller to set
     */
    public void setController(PersistenceEnabledController controller) {
        this.controller = controller;
    }
}
